#define xuser mixc::powerful_cat
#include"algo/sort.hpp"
#include"docker/page_array.hpp"
#include"io/dir.hpp"
#include"io/file.hpp"
#include"lang/cxx/clone.hpp"
#include"lang/cxx/format.hpp"
#include"lang/cxx/index_of_prefix.hpp"
#include"lang/cxx/index_of_suffix.hpp"
#include"lang/cxx.hpp"
#include"mixc.hpp"
#include"utils/static_length_of.hpp"

namespace xuser{
    bool g_is_cxx_file;
    char g_buffer[1024 * 16];
    char g_path_buffer[1204 * 16];
    c08  g_path(g_path_buffer, 0);

    void foreach(){
        dir{"."}.subdirs().foreach([&](asciis folder){
            c08 folder_name{folder};
            if (folder_name.index_of_prefix({".", "private", "draft", "trash"}) != not_exist){
                return;
            }

            folder_name.clone([](uxx length){
                auto old_length     = uxx(g_path->length);
                g_path              = g_path.elongate(length + 1);
                auto buffer         = g_path.backward(old_length);
                buffer[length]      = '/';
                return (char *)buffer;
            });

            dir{folder_name}.as_cwd();
            foreach();
            dir{".."}.as_cwd();
            g_path                  = g_path.shorten(folder_name->length + 1);
        });

        auto    buffer_ptr          = g_buffer;
        auto && list                = page_array<c08>{};

        dir{"."}.subfiles().foreach([&](asciis name){

            // 遍历子文件
            c08 header_file         = name;
            if (header_file.index_of_prefix({"xgen.", "override.", "+."}) != not_exist){
                return;
            }

            if (header_file.index_of_suffix({ g_is_cxx_file ? ".cxx" : ".hpp"}) == not_exist){
                return;
            }

            c08 line = c08{"#include\"\v\v\"" xlocal_endl}.format(g_path, header_file, [&](uxx length) -> char * {
                if (buffer_ptr + length > g_buffer + static_length_of(g_buffer)){
                    xhint("out of mem");
                    throw;
                }

                auto result         = buffer_ptr;
                buffer_ptr[length]  = '\0';
                buffer_ptr         += length + 1/*\0*/;
                return result;
            });

            list.push(line);
        });

        if (list->length == zero){
            return;
        }

        auto && plus = file{ g_is_cxx_file ? "./+.cxx.tmp" : "./+.hpp.tmp"};

        // 按字典序排序
        sort::heap(list, xcmp(c08){
            return left.compare(right);
        });

        // 移除旧文件
        plus.remove();

        // 写入新的文件内容
        list.foreach([&](c08 line){
            plus.write<char>(line);
        });

        // 先关闭
        plus.close();

        // 再重命名
        plus.move_to_forcedly(g_is_cxx_file ? "./+.cxx" : "./+.hpp");
    }

    xinit(xuser::the_main){
        using namespace xuser;

        if (env::args->length < uxx(2)){
            xhint("please input the Mix-c project full root path");
            return;
        }

        auto root               = env::args[1];
        auto valid              = dir{root}.as_cwd();
        xhint(root, valid);

        if (valid == bstate_t::fail){
            xhint("Mix-C root path invalid");
            return;
        }

        if (g_is_cxx_file = env::args->length > uxx(2); g_is_cxx_file){
            c08(env::args[2]).clone([](uxx length){
                g_path          = g_path.elongate(length);
                return g_path_buffer;
            });

            dir{g_path}.as_cwd();
        }

        // ls -F | grep "/$"
        foreach();
    };
}
